#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/sched.h>

#define DEVICE_NAME "deadlock_dev"
static int major;
static struct class *cls;
static spinlock_t my_spinlock;

/********************** 死锁场景选择 **********************/
// 取消注释其中一个场景进行测试
 #define SCENARIO_1  // 递归加锁
// #define SCENARIO_2  // 无限循环
// #define SCENARIO_3  // 长时间操作
//#define SCENARIO_4    // 主动调度

static int device_open(struct inode *inode, struct file *filp) {
#ifdef SCENARIO_1
    /* 场景1：递归加锁 */
    spin_lock(&my_spinlock);
    spin_lock(&my_spinlock); // 第二次加锁导致死锁
    printk(KERN_INFO "Double lock acquired\n");
    spin_unlock(&my_spinlock);
    spin_unlock(&my_spinlock);

#elif defined(SCENARIO_2)
    /* 场景2：无限循环 */
    spin_lock(&my_spinlock);
    while(1) { 
        // 无限循环阻止锁释放
        printk(KERN_INFO "Infinite loop holding lock\n");
        mdelay(1000); 
    }
    spin_unlock(&my_spinlock);

#elif defined(SCENARIO_3)
    /* 场景3：长时间操作 */
    spin_lock(&my_spinlock);
    int i;
    for (i = 0; i < 1000000; i++) {
        // 模拟长时间操作
        printk(KERN_INFO "Long operation %d\n", i);
    }
    spin_unlock(&my_spinlock);

#elif defined(SCENARIO_4)
    /* 场景4：主动调度 */
    spin_lock(&my_spinlock);
    printk(KERN_INFO "Calling schedule() with lock held\n");
    schedule();  // 主动触发调度
    spin_unlock(&my_spinlock);
#endif

    return 0;
}

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = device_open,
};

static int __init spinlock_init(void) {
    spin_lock_init(&my_spinlock);
    major = register_chrdev(0, DEVICE_NAME, &fops);
    #include <linux/version.h>

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
    // 旧版内核：传递 THIS_MODULE
    cls = class_create(THIS_MODULE, DEVICE_NAME);
#else
    // 新版内核：仅传递类名称
    cls = class_create(DEVICE_NAME);
#endif
    device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
    printk(KERN_INFO "Device created\n");
    return 0;
}

static void __exit spinlock_exit(void) {
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    unregister_chrdev(major, DEVICE_NAME);
    printk(KERN_INFO "Device removed\n");
}

module_init(spinlock_init);
module_exit(spinlock_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Spinlock Deadlock Demonstration Driver");